
"""
{  1: { 
      Readable: Event,
      Writable: Event
  },
  2: {
      Readable: Event,
      Writable: Event
  }
}
"""

from event import Event
class FileNoMap:
    def __init__(self):
        self.__map = {}
    def contains_fileno(self, fileno):
        return fileno in self.__map
    def contains_fileno_type(self, fileno, ev_type):
        return fileno in self.__map and ev_type in self.__map[fileno]

    def add(self, fileno, ev_type, ev):
        if fileno not in self.__map:
           self.__map[fileno] = { ev_type : ev} 
        else:
            sub_map = self.__map[fileno]
            if ev_type not in sub_map:
                sub_map[ev_type] = ev
            else:
                raise KeyError(f"fileno:{fileno} already exists")

    def remove(self, fileno, ev_type):
        if fileno in self.__map:
            sub_map = self.__map[fileno]
            if ev_type in sub_map:
                del sub_map[ev_type]
                if len(sub_map) == 0:
                    del self.__map[fileno]
            else:
                raise KeyError(f"map[{fileno}]:[{ev_type}] not in map")
        else:
            raise KeyError(f"fileno:{fileno} not exists in map")

    def __len__(self):
        return len(self.__map)
    def count(self, fileno):
        if fileno in self.__map:
            return len(self.__map[fileno])
        else:
            raise KeyError(f"fileno:{fileno} not exists in map")

    def get_event_type(self, fileno):
        if fileno in self.__map:
            sub_map = self.__map[fileno]
            if sub_map is not None and len(sub_map) >= 1:
                return iter(sub_map.keys()).__next__()
            else:
                raise ValueError("len of map[{fileno}] = 0 or 1 or None")
        else:
            raise KeyError(f"fileno:{fileno} not exists in map")

    def get_readable_event(self, fileno):
        if fileno in self.__map:
            return self.__map[fileno].get(Event.Type.Readable)
        else:
            raise KeyError(f"fileno:{fileno} not exists in map")
    def get_writable_event(self, fileno):
        if fileno in self.__map:
            return self.__map[fileno].get(Event.Type.Writable)
        else:
            raise KeyError(f"fileno:{fileno} not exists in map")

    def clear(self):
        self.__map.clear()
    def __str__(self):
        ret = ""
        for k, v in self.__map.items():
            ret += "{}:".format(k.fileno())
            for sk, sv in v.items():
               ret += f"{sk}:{sv},"
            ret += "||"
        return ret

import unittest
class TestFileNoMap(unittest.TestCase):
    def test_main(self):
        fmap = FileNoMap()
        obj = object()
        fmap.add(1, 1, obj)
        self.assertTrue(fmap.contains_fileno(1))
        self.assertTrue(fmap.contains_fileno_type(1, 1))
        self.assertFalse(fmap.contains_fileno(2))
        self.assertFalse(fmap.contains_fileno_type(1, 2))
        self.assertEqual(1, len(fmap))
        self.assertEqual(1, fmap.count(1))

        self.assertEqual(1, fmap.get_event_type(1))

        fmap.add(1, 2, obj)
        self.assertEqual(1, len(fmap))
        self.assertEqual(2, fmap.count(1))
        self.assertTrue(fmap.contains_fileno(1))
        self.assertTrue(fmap.contains_fileno_type(1, 2))

        self.assertEqual(1, fmap.get_event_type(1))

        fmap.remove(1, 1)
        self.assertFalse(fmap.contains_fileno_type(1, 1))
        self.assertEqual(1, fmap.count(1))
        self.assertEqual(1, len(fmap))

        self.assertTrue(fmap.contains_fileno(1))
        self.assertTrue(fmap.contains_fileno_type(1, 2))

        fmap.remove(1, 2)
        self.assertEqual(0, len(fmap))
        self.assertFalse(fmap.contains_fileno_type(1, 2))
        self.assertFalse(fmap.contains_fileno(1))

if __name__ == "__main__":
    #logging.basicConfig(level=logging.DEBUG)
    unittest.main(verbosity=2)
